package webhook

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"alfred/database"
	"alfred/executor"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/webhooks/v6/gitlab"
)

type WebhookHandler struct {
	db       *database.DB
	executor *executor.Executor
	hook     *gitlab.Webhook
	secret   string
}

// NewWebhookHandler 创建新的Webhook处理器
func NewWebhookHandler(db *database.DB, executor *executor.Executor, secret string) *WebhookHandler {
	hook, err := gitlab.New(gitlab.Options.Secret(secret))
	if err != nil {
		log.Fatalf("Failed to create GitLab webhook: %v", err)
	}

	return &WebhookHandler{
		db:       db,
		executor: executor,
		hook:     hook,
		secret:   secret,
	}
}

// HandleWebhook 处理GitLab webhook事件
func (wh *WebhookHandler) HandleWebhook(c *gin.Context) {
	payload, err := wh.hook.Parse(c.Request, gitlab.PushEvents, gitlab.MergeRequestEvents)
	if err != nil {
		if err == gitlab.ErrEventNotFound {
			// 忽略不支持的事件类型
			c.JSON(http.StatusOK, gin.H{"message": "Event not supported"})
			return
		}
		log.Printf("Failed to parse webhook: %v", err)
		c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse webhook"})
		return
	}

	switch payload := payload.(type) {
	case gitlab.PushEventPayload:
		wh.handlePushEvent(c, payload)
	case gitlab.MergeRequestEventPayload:
		wh.handleMergeRequestEvent(c, payload)
	default:
		c.JSON(http.StatusOK, gin.H{"message": "Event type not handled"})
	}
}

// handlePushEvent 处理Push事件
func (wh *WebhookHandler) handlePushEvent(c *gin.Context, payload gitlab.PushEventPayload) {
	log.Printf("Received push event for branch: %s, commit: %s", payload.Ref, payload.After)

	// 提取分支名称（去掉refs/heads/前缀）
	branch := payload.Ref
	if len(branch) > 11 && branch[:11] == "refs/heads/" {
		branch = branch[11:]
	}

	// 只处理main分支和release-*分支
	if !wh.shouldProcessBranch(branch) {
		log.Printf("Ignoring push event for branch: %s (not main or release-*)", branch)
		c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Branch %s is not configured for processing", branch)})
		return
	}

	// 获取仓库URL（优先使用HTTP URL）
	repoURL := payload.Project.GitHTTPURL
	if repoURL == "" {
		repoURL = payload.Project.GitSSHURL
	}

	// 根据分支和仓库URL查找对应的Flow
	flow, err := wh.db.GetFlowByBranchAndRepo(branch, repoURL)
	if err != nil {
		// 降级到只匹配分支（向后兼容）
		flow, err = wh.db.GetFlowByBranch(branch)
		if err != nil {
			log.Printf("No flow found for branch %s in repo %s: %v", branch, repoURL, err)
			c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("No flow configured for branch %s in repository %s", branch, repoURL)})
			return
		} else {
			log.Printf("Warning: Found flow by branch only, consider updating to include repo_url for branch %s", branch)
		}
	}

	// 异步执行Flow
	go func() {
		if err := wh.executor.ExecuteFlow(flow.ID, payload.After, branch); err != nil {
			log.Printf("Failed to execute flow %s: %v", flow.Name, err)
		}
	}()

	c.JSON(http.StatusOK, gin.H{
		"message":   "Flow execution started",
		"flow_id":   flow.ID,
		"flow_name": flow.Name,
		"branch":    branch,
		"commit_id": payload.After,
	})
}

// handleMergeRequestEvent 处理合并请求事件
func (wh *WebhookHandler) handleMergeRequestEvent(c *gin.Context, payload gitlab.MergeRequestEventPayload) {
	// 只处理合并事件
	if payload.ObjectAttributes.Action != "merge" {
		c.JSON(http.StatusOK, gin.H{"message": "Only merge actions are handled"})
		return
	}

	targetBranch := payload.ObjectAttributes.TargetBranch
	log.Printf("Received merge request event for target branch: %s", targetBranch)

	// 只处理main分支和release-*分支
	if !wh.shouldProcessBranch(targetBranch) {
		log.Printf("Ignoring merge request event for target branch: %s (not main or release-*)", targetBranch)
		c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Target branch %s is not configured for processing", targetBranch)})
		return
	}

	// 获取仓库URL（优先使用HTTP URL）
	repoURL := payload.Project.GitHTTPURL
	if repoURL == "" {
		repoURL = payload.Project.GitSSHURL
	}

	// 根据目标分支和仓库URL查找对应的Flow
	flow, err := wh.db.GetFlowByBranchAndRepo(targetBranch, repoURL)
	if err != nil {
		// 降级到只匹配分支（向后兼容）
		flow, err = wh.db.GetFlowByBranch(targetBranch)
		if err != nil {
			log.Printf("No flow found for branch %s in repo %s: %v", targetBranch, repoURL, err)
			c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("No flow configured for branch %s in repository %s", targetBranch, repoURL)})
			return
		} else {
			log.Printf("Warning: Found flow by branch only, consider updating to include repo_url for branch %s", targetBranch)
		}
	}

	// 异步执行Flow
	go func() {
		if err := wh.executor.ExecuteFlow(flow.ID, payload.ObjectAttributes.LastCommit.ID, targetBranch); err != nil {
			log.Printf("Failed to execute flow %s: %v", flow.Name, err)
		}
	}()

	c.JSON(http.StatusOK, gin.H{
		"message":   "Flow execution started",
		"flow_id":   flow.ID,
		"flow_name": flow.Name,
		"branch":    targetBranch,
		"commit_id": payload.ObjectAttributes.LastCommit.ID,
	})
}

// shouldProcessBranch 检查是否应该处理该分支
func (wh *WebhookHandler) shouldProcessBranch(branch string) bool {
	// 处理main分支
	if branch == "main" {
		return true
	}

	// 处理release-*分支
	if strings.HasPrefix(branch, "release-") {
		return true
	}

	// 其他分支不处理
	return false
}

// extractBranchName 从事件中提取分支名
func (wh *WebhookHandler) extractBranchName(event interface{}) string {
	switch e := event.(type) {
	case gitlab.PushEventPayload:
		return e.Ref[11:] // 移除 "refs/heads/" 前缀
	case gitlab.MergeRequestEventPayload:
		return e.ObjectAttributes.TargetBranch
	default:
		return ""
	}
}

// SetupWebhookRoutes 设置webhook路由
func SetupWebhookRoutes(router *gin.Engine, wh *WebhookHandler) {
	// GitLab webhook端点
	router.POST("/webhook/gitlab", wh.HandleWebhook)

	// 健康检查端点
	router.GET("/webhook/health", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"status": "healthy"})
	})
}
